using System.Linq;
using EPiServer.Core; 
using System; 
namespace EPiBoost.Core.CustomProperties.EnumSelector
{
	/// <summary>
	/// Custom PropertyData implementation
	/// </summary>
	[Serializable]
	public class PropertyEnumSelectorBase<T> : PropertyLongString where T : struct
	{
		private SelectedEnumCollection<T> _selectedEnums;

        public PropertyEnumSelectorBase()
            : this(new SelectedEnumCollection<T>()) {}

        public PropertyEnumSelectorBase(SelectedEnumCollection<T> _selectedEnums)
        {
            this._selectedEnums = _selectedEnums;

            if(this._selectedEnums == null)
                this._selectedEnums = new SelectedEnumCollection<T>();
        }
		 
        public SelectedEnumCollection<T> SelectedEnums
        {
            get
            {
                return _selectedEnums;
            }

            set
            {
                ThrowIfReadOnly();
                
                if (value == null || !value.Any())
                {
                    Clear();
                    return;
                }

                _selectedEnums = value;
                
                Modified();
            }
        }

        public override PropertyData ParseToObject(string value)
        {
            SelectedEnumCollection<T> parsedKeywords = ParseSelectedEnumCollection(value);
            
            return new PropertyEnumSelectorBase<T>(parsedKeywords);
        }

        public override void ParseToSelf(string value)
        {
            Value = ParseSelectedEnumCollection(value);
        }

		private SelectedEnumCollection<T> ParseSelectedEnumCollection(string value)
        {
            if (QualifyAsNullString(value))
                return new SelectedEnumCollection<T>();

            return SelectedEnumCollection<T>.Parse(value);
        }

        protected override void SetDefaultValue()
        {
            ThrowIfReadOnly();
            _selectedEnums = new SelectedEnumCollection<T>();
        }

        public override PropertyData CreateWritableClone()
        {
            var clone = (PropertyEnumSelectorBase<T>) base.CreateWritableClone();
            
            clone._selectedEnums = _selectedEnums.CreateWritableClone();
            
            return clone;
        }

        public override PropertyData Copy()
        {
            var copy = (PropertyEnumSelectorBase<T>) base.Copy();

            copy._selectedEnums = _selectedEnums.Copy();

            return copy;
        }

        public override object SaveData(PropertyDataCollection properties)
        {
            return _selectedEnums.ToString();
        }

        public override IPropertyControl CreatePropertyControl()
        {
            return new SingleEnumSelectorControl<T>();
        }

        public override object Value
        {
            get
            {
                if (IsNull)
                    return null;

                return _selectedEnums; 
            }
            set
            {
                SetPropertyValue(value, () =>
                {
                    if (value is SelectedEnumCollection<T>)
                    {
                        SelectedEnums = (SelectedEnumCollection<T>) value;
                    }
                    else if (value is string)
                    {
                        ParseToSelf((string)value);
                    }
                    else
                    {
                        throw new ArgumentException(
                            "Passed object must be of type SelectedEnums or "
                            + "a string that can be de-serialized to a "
                            + "SelectedEnums object.");
                    }
                });
            }
        }

        public override bool IsNull
        {
            get { return _selectedEnums == null || _selectedEnums.Count() == 0; }
        }

        public override bool IsModified
        {
            get
            {
                return base.IsModified || _selectedEnums.IsModified;
            }
            set
            {
                ThrowIfReadOnly();
                _selectedEnums.IsModified = value;
                base.IsModified = value;
            }
        }

        public override Type PropertyValueType
        {
            get { return typeof(string); }
        }

        public override PropertyDataType Type
        {
            get { return PropertyDataType.LongString; }
        }
    }
	
}
